/*!
 * \file json_comm.c
 *
 * \brief json 数据收集
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 *
 * \version 1.0
 * \author geyh
 * \date 2017/03/02
 *
 */


#include <module_comm.h>
#include <conntrack.h>
#include <module.h>
#include <sys/time.h>
#include <frreport_comm.h>
#include <frlog.h>
#include <frct_comm.h>
#include <frjson_checker.h>
#include <frservice_comm.h>
#include "json_comm.h"
#include "json_data_analyze.h"
#include "config.h"

extern void *g_p_apm_context;

/*!
 * json数据 request数据解析
 *
 * \param p_st_packet      (协议分析入力数据)
 *        p_st_private     (私有数据)
 *        p_st_conn        (ct信息)
 *        p_st_hash_report (上报信息)
 *
 * \return  FR_SUCC:成功
 *          FR_FAIL:失败
 *
 */
int frjson_req_analyze(Apm_packet *p_st_packet, L7session_json_private *p_st_private
                       , Conntrack *p_st_conn, Frhash_header *p_st_hash_report)
{
    char *p_tcp_body = p_st_packet->p_payload;
    unsigned int ui_tcp_body_len = p_st_packet->ui_payload_len;
    L4_transaction *p_st_l4_trans = &p_st_private->st_l4_trans;
    Frreport_body_data *p_st_body_data = NULL;
    Frreport_data *p_st_report_data = NULL;
    unsigned long ul_seq = 0, ul_tmp = 0;
    char *p_tmp = NULL;
    unsigned int ui_tmp_len = 0;
    Frbyte_Packet *p_packet = NULL;
    int i_json_format = 0;

    if(p_tcp_body == NULL || ui_tcp_body_len == 0)
        return APM_L7_ANALYZE_FAIL;

    //时间信息处理
    if(p_st_private->uc_start_char == '\0')
    {
        //首包开头符
        if(p_tcp_body[0] == '{')
        {
            p_st_private->uc_start_char = '{';
            p_st_private->uc_end_char = '}';
        }
        else if(p_tcp_body[0] == '[')
        {
            p_st_private->uc_start_char = '[';
            p_st_private->uc_end_char = ']';
        }
        else
        {
            return APM_L7_ANALYZE_FAIL;
        }

        //时间信息保存
        p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

        //初始化信息
        if(p_st_private->p_st_data)
        {
            memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
            bytebuff_free(&p_st_private->p_st_data);
        }

    }

    if(p_st_private->p_st_data == NULL)
        p_st_private->p_st_data = bytebuff_creat();

    p_packet = p_st_private->p_st_data;
    bytebuff_add(p_packet, p_tcp_body, ui_tcp_body_len);
    p_st_l4_trans->l_request_bytes += ui_tcp_body_len;

    //判断json是否结束
    if(p_tcp_body[ui_tcp_body_len - 1] == p_st_private->uc_end_char)
    {
        ui_tmp_len = (unsigned int)bytebuff_remaining(p_packet);
        p_tmp = (char *) frmalloc(ui_tmp_len + 1);

        bytebuff_peek_bytes(p_packet, p_tmp, ui_tmp_len);
        p_tmp[ui_tmp_len] = '\0';

        if(frjson_format_detect((unsigned char *) p_tmp, ui_tmp_len) == FR_NO)
        {
            frfree(p_tmp);
            return APM_L7_ANALYZE_TODO;
        }

    }
    else
        return APM_L7_ANALYZE_TODO;

    p_st_body_data = frreport_body_new_l7(p_st_conn);
    if(p_st_body_data == NULL)
    {
        frfree(p_tmp);
        FRLOG_ERROR_DETAIL("malloc fail");
        return APM_L7_ANALYZE_FAIL;
    }

    if(p_st_private->i_json_format == 0)
    {
        if(frthrift_data_detect(p_tmp) == FR_YES)
        {
            p_st_private->i_json_format = JSON_THRIFT;
            if(p_st_private->pf_free == NULL)
                p_st_private->pf_free = frjson_thrift_private_free;
            else
                goto ERROR;

            i_json_format = JSON_THRIFT;
            frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, &i_json_format, sizeof(int));

        }
        else
        {
            p_st_private->i_json_format = JSON_OTHER;
            i_json_format = JSON_OTHER;
            frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, &i_json_format, sizeof(int));
        }

    }

    // thrift json 格式
    if(p_st_private->i_json_format == JSON_THRIFT)
    {
        frthrift_json_analyze(p_tmp, p_st_body_data, p_st_private, FR_YES, (char *)"request.rpc");

        frfree(p_tmp);
        p_tmp = NULL;
    }
    else
    {
        if(frreport_body_l7_add_int(p_st_body_data, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1) == FR_FAIL)
            goto ERROR;
    }

    ul_seq = frct_seq_increase(p_st_conn);
    if(frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_REQ_ID, ul_seq) == FR_FAIL)
        goto ERROR;

    if(frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_l4_trans->st_request_time_first_byte) == FR_FAIL)
        goto ERROR;

    //request 结束时间
    p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    //request_time_us
    ul_tmp = (unsigned long)frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &p_st_packet->st_timestamp);
    if(frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    //响应字节数
    if(frreport_body_l7_add_long(p_st_body_data, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_l4_trans->l_request_bytes) == FR_FAIL)
        goto ERROR;

    if(frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
        goto ERROR;

    p_st_private->p_report_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_body_data);
    p_st_private->p_report_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_body_data);

    //数据上报
    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
    if(p_st_report_data == NULL)
        goto ERROR;

    if(frreport_data_add_body(p_st_report_data, p_st_body_data) == FR_FAIL)
        goto ERROR;

    p_st_body_data = NULL;

    if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
        goto ERROR;

    if(p_st_private->i_json_format == JSON_THRIFT)
        frjson_thrift_data_add(p_st_private);


    bytebuff_free(&p_st_private->p_st_data);
    p_st_private->uc_start_char = '\0';

    return APM_L7_ANALYZE_SUCC;

ERROR:

    memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
    bytebuff_free(&p_st_private->p_st_data);

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    if(p_st_body_data)
        frreport_body_free(&p_st_body_data);

    if(p_tmp)
        frfree(p_tmp);

    return APM_L7_ANALYZE_FAIL;

}

/*!
 * json数据 response数据解析
 *
 * \param p_st_packet      (协议分析入力数据)
 *        p_st_private     (私有数据)
 *        p_st_conn        (ct信息)
 *        p_st_hash_report (上报信息)
 *
 * \return  FR_SUCC:成功
 *          FR_FAIL:失败
 *
 */
int frjson_resp_analyze(Apm_packet *p_st_packet, L7session_json_private *p_st_private
                       , Conntrack *p_st_conn, Frhash_header *p_st_hash_report)
{
    char *p_tcp_body = p_st_packet->p_payload;
    unsigned int ui_tcp_body_len = p_st_packet->ui_payload_len;
    L4_transaction *p_st_l4_trans = &p_st_private->st_l4_trans;
    Frreport_body_data *p_st_body_data = NULL;
    Frreport_data *p_st_report_data = NULL;
    unsigned long ul_tmp = 0;
    char *p_tmp = NULL;
    unsigned int ui_tmp_len = 0;
    Frbyte_Packet *p_packet = NULL;

    if(p_tcp_body == NULL || ui_tcp_body_len == 0)
        return APM_L7_ANALYZE_FAIL;

    //时间信息处理
    if(p_st_private->uc_start_char == '\0')
    {
        //首包开头符
        if(p_tcp_body[0] == '{')
        {
            p_st_private->uc_start_char = '{';
            p_st_private->uc_end_char = '}';
        }
        else if(p_tcp_body[0] == '[')
        {
            p_st_private->uc_start_char = '[';
            p_st_private->uc_end_char = ']';
        }
        else
        {
            return APM_L7_ANALYZE_FAIL;
        }

        //时间信息保存
        p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

    }

    //只有response  不上报
    if(p_st_private->i_json_format == JSON_OTHER)
    {
        if(p_st_private->p_report_comm == NULL)
            goto ERROR;
    }

    if(p_st_private->p_st_data == NULL)
    {
        p_st_private->p_st_data = bytebuff_creat();
        if(p_st_private->p_st_data == NULL)
        {
            FRLOG_ERROR_DETAIL_LIMIT("malloc fail");
            goto ERROR;
        }
    }

    p_packet = p_st_private->p_st_data;
    bytebuff_add(p_packet, p_tcp_body, ui_tcp_body_len);
    p_st_l4_trans->l_response_bytes += ui_tcp_body_len;

    //判断json是否结束
    if(p_tcp_body[ui_tcp_body_len - 1] == p_st_private->uc_end_char)
    {
        ui_tmp_len = (unsigned int)bytebuff_remaining(p_packet);
        p_tmp = (char *) frmalloc(ui_tmp_len + 1);

        bytebuff_peek_bytes(p_packet, p_tmp, ui_tmp_len);
        p_tmp[ui_tmp_len] = '\0';

        if(frjson_format_detect((unsigned char *) p_tmp, ui_tmp_len) == FR_NO)
        {
            frfree(p_tmp);
            return APM_L7_ANALYZE_TODO;
        }

    }
    else
        return APM_L7_ANALYZE_TODO;

    p_st_body_data = frreport_body_new_l7(p_st_conn);
    if(p_st_body_data == NULL)
    {
        FRLOG_ERROR_DETAIL("malloc fail");
        return APM_L7_ANALYZE_FAIL;
    }

    // thrift json 格式
    if(p_st_private->i_json_format == JSON_THRIFT)
    {
        frthrift_json_analyze(p_tmp, p_st_body_data, p_st_private, FR_NO, (char *)"response.rpc");

        frfree(p_tmp);
        p_tmp = NULL;

        if(frjson_thrift_data_set(p_st_private) == FR_FAIL)
            goto ERROR;
    }
    else
    {
        //resp code 上报
        frreport_body_l7_add_long(p_st_body_data, APM_REPORT_KEY_RESP_CODE, 0);
    }

    //comm
    FRREPORT_BODY_L7LIST_SET_COMM(p_st_body_data, &p_st_private->p_report_comm);

    //把req数据链表添加到resp中
    FRREPORT_BODY_L7LIST_SET_REQ(p_st_body_data, &p_st_private->p_report_req);

    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    //response start time
    if(frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_l4_trans->st_response_time_first_byte) == FR_FAIL)
        goto ERROR;

    //server_time_us
    ul_tmp = (unsigned long)frtime_diff(&p_st_private->st_l4_trans.st_request_time, &p_st_l4_trans->st_response_time_first_byte);
    if(frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    if(frreport_body_l7_add_long(p_st_body_data, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
        goto ERROR;

    if(frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_l4_trans->st_response_time) == FR_FAIL)
        goto ERROR;

    ul_tmp = (unsigned long)frtime_diff(&p_st_l4_trans->st_response_time_first_byte, &p_st_l4_trans->st_response_time);
    if(frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
    if(p_st_report_data == NULL)
        goto ERROR;

    if(frreport_data_add_body(p_st_report_data, p_st_body_data) == FR_FAIL)
        goto ERROR;

    p_st_body_data = NULL;

    if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
        goto ERROR;


    memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
    bytebuff_free(&p_st_private->p_st_data);
    p_st_private->uc_start_char = '\0';

    return APM_L7_ANALYZE_SUCC;


ERROR:
    memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
    bytebuff_free(&p_st_private->p_st_data);
    p_st_private->uc_start_char = '\0';

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    if(p_st_body_data)
        frreport_body_free(&p_st_body_data);

    if(p_tmp)
        frfree(p_tmp);

    return APM_L7_ANALYZE_FAIL;

}

